import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.Socket;
import java.net.UnknownHostException;

public class FileTransferer
{
    public static final int fileport = 20000;
    public static final String savePath = "/home/ubuntu/apps";

    public static class FileData implements Serializable
    {
        private static final long serialVersionUID = 974788527580801181L;
        String name;
        byte[] content;
        String command;

        FileData()
        {

        }

        FileData(String name, byte[] content, String command)
        {
            this.name = name;
            this.content = content;
            this.command = command;
        }
    }
    
    public static void send(Socket soc, String fileName, InputStream in)
    {
        send(soc, fileName, in, null);
    }
    
    public static void send(Socket soc, String fileName, InputStream in, String command)
    {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        BufferedOutputStream out = new BufferedOutputStream(bos);
        BufferedInputStream bin = new BufferedInputStream(in);
        
        byte[] buffer = new byte[1024];
        
        int n;
        try
        {
            while((n = bin.read(buffer)) != -1)
            {
                out.write(buffer, 0, n);
            }
            out.flush();
            
            send(soc, fileName, bos.toByteArray(), command);
        }
        catch (IOException e)
        {
            System.out.println("Sending file failed!");
            e.printStackTrace();
        }
    }
    
    public static void send(Socket soc, File file)
    {
        send(soc, file, null);
    }

    public static void send(Socket soc, File file, String command)
    {
        FileData data = new FileData();
        int size = (int) file.length();
        data.name = file.getName();
        data.command = (command == null) ? (savePath + data.name) : command;

        try
        {
            BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));
            data.content = new byte[size];
            in.read(data.content);
            in.close();
            send(soc, data);
        }
        catch (IOException e)
        {
            System.out.println("Sending file failed!");
            e.printStackTrace();
        }
    }
    
    public static void send(Socket soc, String fileName, byte[] content)
    {
        send(soc, fileName, content, null);
    }

    public static void send(Socket soc, String fileName, byte[] content, String command)
    {
        FileData data = new FileData(fileName, content, (command == null) ? (savePath + fileName) : command);
        try
        {
            send(soc, data);
        }
        catch (IOException e)
        {
            System.out.println("Sending file failed!");
            e.printStackTrace();
        }
    }

    private static void send(Socket soc, FileData data) throws IOException
    {
        ObjectOutputStream out = new ObjectOutputStream(soc.getOutputStream());
        out.writeObject(data);
        out.close();
    }

    public static FileData receive(Socket soc)
    {
        FileData data = null;
        try
        {
            ObjectInputStream oin = new ObjectInputStream(soc.getInputStream());
            data = (FileData) oin.readObject();

            oin.close();
            
            Logger.log(data.name + " received. Size: " + data.content.length);
        }
        catch (IOException e)
        {
            System.out.println("Sending file failed!");
            e.printStackTrace();
        }
        catch (ClassNotFoundException e)
        {
            e.printStackTrace();
        }
        return data;
    }
    
    public static void main(String[] args) throws UnknownHostException, IOException
    {
        Socket soc = new Socket(args[0], fileport);
        if (args.length == 2)
            send(soc, args[1], new FileInputStream(new File(args[1])));
        else if (args.length == 3)
            send(soc, new File(args[1]), args[2]);
        else
            System.out.println("Usage: java FileTransferer <host> <file> [start command]");
        soc.close();
    }
}
